package org.maven.dependencybrowser.controller.model;
/**********************************************************************
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Contributors:

**********************************************************************/
import org.maven.dependencybrowser.model.Artifact;
import org.maven.dependencybrowser.model.ArtifactInstanceMap;

import java.util.*;

/**
 * Holds and indexed, sortable list of artifact versions.  Provides selection, deselection
 * and sort order functionality.
 */
public class ArtifactVersionsListManager
{
    private List<ArtifactInstanceMap> selected;
    private List<ArtifactInstanceMap> ordered;
    private Map<String, ArtifactInstanceMap> indexed;
    private ArtifactInstanceMapComparator artifactInstanceMapComparator;
    public static final int DEFAULT_ORDER_BY = 1;

    public ArtifactVersionsListManager()
    {
        ordered = new ArrayList<ArtifactInstanceMap>();
        indexed = new HashMap<String, ArtifactInstanceMap>();
        artifactInstanceMapComparator = new ArtifactInstanceMapComparator();
        selected = new ArrayList<ArtifactInstanceMap>();
    }

    public ArtifactInstanceMap get(int index)
    {
        if ( index >= 0 && index < ordered.size() )
        {
            return ordered.get(index);
        }
        else return null;
    }

    public void select(int index)
    {
        List<ArtifactInstanceMap> newlySelectedMaps = new ArrayList<ArtifactInstanceMap>();
        ArtifactInstanceMap mapAtIndex = get(index);
        if ( mapAtIndex != null )
        {
            newlySelectedMaps.add(mapAtIndex);
        }
        select(newlySelectedMaps);
    }
    /**
     * Reselect artifact maps
     * @param newlySelected collection of newly selected artifact instance maps
     */
    public void select(Collection<ArtifactInstanceMap> newlySelected)
    {
        for (Iterator<ArtifactInstanceMap> selectdIterator = selected.iterator(); selectdIterator.hasNext();)
        {
            ArtifactInstanceMap map = selectdIterator.next();
            map.select(false);
            selectdIterator.remove();
        }
        for (ArtifactInstanceMap map : newlySelected)
        {
            map.select(true);
            selected.add(map);
        }
    }

    public int size()
    {
        return ordered.size();
    }

    ArtifactInstanceMap add(Artifact instance)
    {
        String version = instance.getVersion();
        // add artifact reference to the instance map
        String fullKey = instance.getGroupId() + ":" + instance.getArtifactId() + ":" + version;
        ArtifactInstanceMap map = indexed.get(fullKey);
        if (map == null)
        {
            map = new ArtifactInstanceMap(instance);
            indexed.put(fullKey, map);
            ordered.add(map);
            Collections.sort(ordered, artifactInstanceMapComparator);
        }
        map.addInstance(instance);
        return map;
    }

    public void setArtifactInstanceMapComparator(int field)
    {
        artifactInstanceMapComparator.setOrderBy(field);
        Collections.sort(ordered, artifactInstanceMapComparator);
    }

    static class ArtifactInstanceMapComparator implements Comparator<ArtifactInstanceMap>
    {
        private int orderBy;
        private boolean reversed;

        ArtifactInstanceMapComparator()
        {
            orderBy = DEFAULT_ORDER_BY;
            reversed = false;
        }

        private int implementReversed(int comparison)
        {
            if (reversed)
            {
                return comparison * -1;
            }
            return comparison;
        }

        public void setOrderBy(int columnIndex)
        {
            if (orderBy != columnIndex)
            {
                orderBy = columnIndex;
                reversed = false;
            }
            else
            {
                reversed = !reversed;
            }
        }

        public int compare(ArtifactInstanceMap map1, ArtifactInstanceMap map2)
        {
            switch (orderBy)
            {
                case 0:
                    return implementReversed(map1.getGroupId().compareToIgnoreCase(map2.getGroupId()));
                case 1:
                    return implementReversed(map1.getArtifactId().compareToIgnoreCase(map2.getArtifactId()));
                case 2:
                    return implementReversed(map1.getVersion().compareToIgnoreCase(map2.getVersion()));
                case 3:
                    return implementReversed(new Integer(map1.getInstances().size()).compareTo(map2.getInstances().size()));
                default:
                    throw new IllegalArgumentException("Field " + orderBy + " not found");
            }
        }
    }
}
